package com.yc.services;

import com.aliyun.oss.OSS;
import com.yc.config.OSSConfig;
import com.yc.exception.FileSizeLimitExceededException;
import com.yc.exception.InvalidFileTypeException;
import lombok.extern.java.Log;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class OSSService {
    // 创建日志记录器
    private static final Logger logger = LoggerFactory.getLogger(OSSService.class);


    @Autowired
    private OSSConfig ossConfig;
    @Autowired
    private OSS ossClient;
    @Autowired
    private StringRedisTemplate redisTemplate;

    // Redis键前缀
    private static final String IMAGE_FINGERPRINT_PREFIX = "image:md5:";
    // 指纹缓存时间（天）
    private static final long FINGERPRINT_EXPIRE_DAYS = 30;

    /**
     * 上传多个文件,返回总url，用逗号进行分割的
     * @param files
     * @return
     */
    public List<String> uploadFiles(MultipartFile[] files) {
//        if(true){
//            throw  new FileSizeLimitExceededException("上传失败：总文件大小不能超过50MB");
//        }
        // 验证总大小
        long totalSize = Arrays.stream(files)
                .mapToLong(MultipartFile::getSize)
                .sum();
        logger.info("文件总大小为:{}",totalSize);
        if (totalSize > ossConfig.getMaxTotalSize()) {
            throw new FileSizeLimitExceededException("上传失败：总文件大小不能超过50MB");
        }

        List<String> urls = new ArrayList<>();

        // 验证每个文件
        for (MultipartFile file : files) {
            // 验证单个文件大小
            logger.info("文件{}大小为:{}",file.getOriginalFilename(),file.getSize());
            if (file.getSize() > ossConfig.getMaxSingleFileSize()) {
                throw new FileSizeLimitExceededException(
                        String.format("文件[%s]超过10MB限制", file.getOriginalFilename())
                );
            }

            // 验证文件类型
            logger.info("文件{}类型为:{}",file.getOriginalFilename(),file.getContentType());
            if (!isAllowedFileType(file.getContentType())) {
                throw new InvalidFileTypeException(
                        String.format("文件[%s]类型不支持，仅允许图片/PDF/Word/Excel",
                                file.getOriginalFilename())
                );
            }
            // 新增：查重校验
            String fileUrl = checkDuplicateAndUpload(file);
            urls.add(fileUrl);
        }
        return urls;
    }

    private String checkDuplicateAndUpload(MultipartFile file) {
        try (InputStream inputStream = file.getInputStream()) {
            // 1. 计算文件MD5指纹
            String md5 = DigestUtils.md5Hex(inputStream);
            String redisKey = IMAGE_FINGERPRINT_PREFIX + md5;

            // 2. 查询Redis是否存在该指纹
            String existingUrl = redisTemplate.opsForValue().get(redisKey);
            if (existingUrl != null) {
                logger.info("文件{}已存在，URL为:{}",file.getOriginalFilename(),existingUrl);
                return existingUrl; // 直接返回已存在的URL
            }

            // 3. 无重复则上传OSS
            logger.info("文件{}不存在，开始上传",file.getOriginalFilename());
            String newUrl = uploadToOSS(file);

            // 4. 将指纹-URL存入Redis
            logger.info("文件{}上传成功，URL为:{}",file.getOriginalFilename(),newUrl);
            redisTemplate.opsForValue().set(
                    redisKey,
                    newUrl,
                    FINGERPRINT_EXPIRE_DAYS,
                    TimeUnit.DAYS
            );

            return newUrl;
        } catch (IOException e) {
            throw new RuntimeException("文件处理失败", e);
        }
    }

    private boolean isAllowedFileType(String mimeType) {
        return Arrays.asList(ossConfig.getAllowedMimeTypes())
                .contains(mimeType.toLowerCase());
    }

    private String uploadToOSS(MultipartFile file) {
        // 获取配置
        String bucketName = ossConfig.getBucketName();
        String endpoint = ossConfig.getEndpoint();

        try {
            // 获取文件原始名称
            String originalFilename = file.getOriginalFilename();

            // 生成新的文件名（防止重复）
            String fileName = "headpics/" + UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));

            // 上传文件流
            ossClient.putObject(bucketName, fileName, file.getInputStream());

            // 返回文件的访问地址
            // 格式：https://bucket-name.endpoint/file-name
            return "https://" + bucketName + "." + endpoint + "/" + fileName;
        } catch (IOException e) {
            throw new RuntimeException("文件上传失败", e);
        }
    }

}
